import { Platform } from 'react-native';
import * as FileSystem from 'expo-file-system';
import * as ImageManipulator from 'expo-image-manipulator';
import { ProcessingOptions } from '../shared/types/app';

/**
 * Image optimizer for handling image processing and compression
 */
export class ImageOptimizer {
    /**
     * Optimizes an image file for sending to API
     * 
     * @param sourceUri URI of the source image file
     * @param options Processing options
     * @returns Promise with the URI of the optimized image
     */
    static async optimize(
        sourceUri: string,
        options: ProcessingOptions['image'] = {}
    ): Promise<string> {
        const {
            maxWidth = 1920,
            maxHeight = 1920,
            quality = 0.85,
            format = 'jpeg'
        } = options;

        try {
            // Get original image dimensions
            const imgInfo = await this.getImageInfo(sourceUri);

            // Check if resizing is needed
            const shouldResize = imgInfo.width > maxWidth || imgInfo.height > maxHeight;

            // Skip optimization if already within limits and format is the same
            if (!shouldResize && sourceUri.toLowerCase().endsWith(format) && imgInfo.size <= 1024 * 1024) {
                console.log('Image already optimized, skipping processing');
                return sourceUri;
            }

            // Calculate new dimensions maintaining aspect ratio
            let newWidth = imgInfo.width;
            let newHeight = imgInfo.height;

            if (shouldResize) {
                if (imgInfo.width > imgInfo.height) {
                    // Landscape orientation
                    newWidth = maxWidth;
                    newHeight = Math.floor(imgInfo.height * (maxWidth / imgInfo.width));
                } else {
                    // Portrait or square orientation
                    newHeight = maxHeight;
                    newWidth = Math.floor(imgInfo.width * (maxHeight / imgInfo.height));
                }
            }

            // Process the image using ImageManipulator
            const result = await ImageManipulator.manipulateAsync(
                sourceUri,
                shouldResize ? [{ resize: { width: newWidth, height: newHeight } }] : [],
                {
                    compress: quality,
                    format: ImageManipulator.SaveFormat[format.toUpperCase()],
                }
            );

            console.log(`Image optimized: ${imgInfo.width}x${imgInfo.height} (${imgInfo.size} bytes) -> ${newWidth}x${newHeight}`);

            return result.uri;
        } catch (error) {
            console.error('Image optimization failed:', error);
            // On error, return original image
            return sourceUri;
        }
    }

    /**
     * Gets information about an image file
     * 
     * @param uri URI of the image file
     * @returns Promise with image information
     */
    static async getImageInfo(uri: string): Promise<{
        width: number;
        height: number;
        size: number;
        type: string;
    }> {
        try {
            // Get basic file info
            const fileInfo = await FileSystem.getInfoAsync(uri, { size: true });

            // Get image dimensions
            const dimensions = await this.getImageDimensions(uri);

            // Determine file type from extension
            const extension = uri.split('.').pop()?.toLowerCase() || '';
            const typeMap: Record<string, string> = {
                'jpg': 'image/jpeg',
                'jpeg': 'image/jpeg',
                'png': 'image/png',
                'gif': 'image/gif',
                'webp': 'image/webp',
                'heic': 'image/heic',
                'heif': 'image/heif'
            };

            return {
                width: dimensions.width,
                height: dimensions.height,
                size: fileInfo.size || 0,
                type: typeMap[extension] || 'image/jpeg'
            };
        } catch (error) {
            console.error('Error getting image info:', error);
            // Return default values on error
            return {
                width: 0,
                height: 0,
                size: 0,
                type: 'image/jpeg'
            };
        }
    }

    /**
     * Gets the dimensions of an image
     * 
     * @param uri URI of the image file
     * @returns Promise with image dimensions
     */
    private static async getImageDimensions(uri: string): Promise<{
        width: number;
        height: number;
    }> {
        return new Promise((resolve, reject) => {
            if (Platform.OS === 'web') {
                // Use Image object in web
                const img = new Image();
                img.onload = () => {
                    resolve({
                        width: img.width,
                        height: img.height
                    });
                };
                img.onerror = (e) => {
                    reject(new Error('Failed to load image for dimensions'));
                };
                img.src = uri;
            } else {
                // Use Image from react-native
                const Image = require('react-native').Image;
                Image.getSize(
                    uri,
                    (width: number, height: number) => {
                        resolve({ width, height });
                    },
                    (error: any) => {
                        reject(error);
                    }
                );
            }
        });
    }

    /**
     * Converts a base64 encoded image to a file URI
     * 
     * @param base64Data Base64 encoded image data
     * @param format Image format
     * @returns Promise with the URI of the saved image
     */
    static async base64ToUri(base64Data: string, format: string = 'jpeg'): Promise<string> {
        try {
            // Remove the data URI prefix if present
            const base64Content = base64Data.includes('base64,')
                ? base64Data.split('base64,')[1]
                : base64Data;

            // Generate a temporary file path
            const timestamp = new Date().getTime();
            const filePath = `${FileSystem.cacheDirectory}temp_image_${timestamp}.${format}`;

            // Write the base64 data to file
            await FileSystem.writeAsStringAsync(filePath, base64Content, {
                encoding: FileSystem.EncodingType.Base64
            });

            return filePath;
        } catch (error) {
            console.error('Error converting base64 to URI:', error);
            throw error;
        }
    }

    /**
     * Converts an image file to base64 encoded string
     * 
     * @param uri URI of the image file
     * @returns Promise with base64 encoded data
     */
    static async uriToBase64(uri: string): Promise<string> {
        try {
            const base64Data = await FileSystem.readAsStringAsync(uri, {
                encoding: FileSystem.EncodingType.Base64
            });

            return base64Data;
        } catch (error) {
            console.error('Error converting URI to base64:', error);
            throw error;
        }
    }
} 